home *** CD-ROM | disk | FTP | other *** search
- //
- // This is a patch for the Inventor 2.0 SoPath code. Three routines
- // had bugs in them that affected some programs:
- // The getLength() would return incorrect results sometimes for nodes
- // with hidden children.
- // The containsPath() method could return incorrect results if both
- // paths contained hidden children
- // And the isRelevantNotification method could cause core dumps when
- // used with SoSF/MFPath fields.
- //
- //
- // To apply this patch, compile this file into a .o and then link
- // the .o before -lInventor. The linker may give a warning.
- // This is normal and expected.
- //
-
- #include <Inventor/SoPath.h>
- #include <Inventor/misc/SoChildList.h>
- #include <Inventor/misc/SoNotification.h>
- #include <Inventor/nodes/SoNode.h>
- #include <Inventor/nodes/SoGroup.h>
-
- ////////////////////////////////////////////////////////////////////////
- //
- // Description:
- // Returns the public length of the path.
- //
- // Use: public
-
- int
- SoPath::getLength() const
- //
- ////////////////////////////////////////////////////////////////////////
- {
- // Cast const away...
- SoPath *This = (SoPath *)this;
-
- // If we aren't sure how many are public, figure it out:
- if (numPublic == -1) {
-
- int lastPublicIndex = 0;
- if (minNumPublic > 1)
- lastPublicIndex = minNumPublic - 1;
-
- // Last test is for the second to last node.
- // If it passes, then lastPublicIndex will be incremented to be the
- // final node, which we don't need to test.
-
- for ( ; lastPublicIndex < (getFullLength() - 1) ; lastPublicIndex++) {
- // Children of this node will be private, so stop.
- if ( ! nodes[lastPublicIndex]->isOfType(SoGroup::getClassTypeId()))
- break;
- }
- This->numPublic = This->minNumPublic = lastPublicIndex + 1;
- }
- return numPublic;
- }
-
- ////////////////////////////////////////////////////////////////////////
- //
- // Description:
- // Returns TRUE if the nodes in the chain in the passed path are
- // contained (in consecutive order) in this path chain.
- //
- // Use: public
-
- SbBool
- SoPath::containsPath(const SoPath *path) const
- //
- ////////////////////////////////////////////////////////////////////////
- {
- int i, j;
-
- // First find the head of the target path in this path
- for (i = 0; i < getFullLength(); i++)
- if (getNode(i) == path->getHead())
- break;
-
- // Head node is not there
- if (i == getFullLength())
- return FALSE;
-
- // If there aren't enough nodes left in this path, then no match
- if (getFullLength() - i < path->getFullLength())
- return FALSE;
-
- // Otherwise, start comparing nodes in the two paths to see if the
- // paths match
- for (j = 0; j < path->getFullLength(); j++)
- if (path->getNode(j) != getNode(i + j))
- return FALSE;
-
- return TRUE;
- }
-
- ////////////////////////////////////////////////////////////////////////
- //
- // Description:
- // Returns TRUE if the given notification list involves a change to
- // a node that affects the path. It is assumed that the last (most
- // recent) node in the list is the head node of the path.
- //
- // Use: internal
-
- SbBool
- SoPath::isRelevantNotification(SoNotList *list) const
- //
- ////////////////////////////////////////////////////////////////////////
- {
- // Trace down the notification list to find the first node (if
- // any) that is not on the path. Stop when we reach the first
- // (in time) record that was at a node in the graph.
-
- const SoNotRec *rec = list->getLastRec();
- const SoNotRec *prevRec = NULL;
- int curIndex = 0;
- SbBool offPath = FALSE;
-
- while (rec != NULL && curIndex < getLength()) {
-
- // Stop if the node in the current record is not the next node
- // in the path
- if (rec->getBase() != getNode(curIndex)) {
- offPath = TRUE;
- break;
- }
-
- // Go to the next record and path node, IF we're following a
- // PARENT notification
- if (rec->getPrevious() != NULL &&
- rec->getPrevious()->getType() != SoNotRec::PARENT) {
- break;
- }
- prevRec = rec;
- rec = rec->getPrevious();
-
- curIndex++;
- }
-
- // If not all notified nodes are on the path, we have to do some
- // extra testing
- if (offPath) {
-
- const SoNode *node;
- int index;
-
- // The "rec" record points to a node that is off the path.
- // Find out the index of this node in the parent node, which
- // is pointed to by the previous record (which is guaranteed
- // to exist and be on the path).
- node = (const SoNode *) rec->getBase();
- index= ((const SoNode *)prevRec->getBase())->getChildren()->find(node);
-
- // If the node is to the right of the path, the change does
- // not affect the path
- if (index > getIndex(curIndex))
- return FALSE;
-
- // If it is to the left, it doesn't affect the path if any of
- // the notification records go through a separator-type object:
- else {
- while (TRUE) {
- if (! node->affectsState())
- return FALSE;
-
- rec = rec->getPrevious();
- if (rec == NULL || rec->getType() != SoNotRec::PARENT)
- break;
-
- node = (const SoNode *) rec->getBase();
- }
- }
- }
-
- // If we made it this far, it's a relevant notification
- return TRUE;
- }
-
-